概述
锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源(有些锁可以允许多个线程并发的访问共享资源,比如读写锁)。在 Lock 接口出现之前,Java 程序是靠 synchronized 关键字实现锁功能的,而 Java SE 5 之后,并发包中新增了 Lock 接口(以及相关实现类)用来实现锁功能,它提供了与 synchronized 关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。虽然它缺少了(通过synchronized块或者方法所提供的)隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的便捷性、可中断的获取锁以及超时获取锁等多种 synchronized 关键字所不具备的同步特性。
和 synchronized 区别
- 尝试非阻塞地获取锁:当前线程尝试获取锁,如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁,如果被其他线程持有,则立即返回false。
- 能被中断地获取锁:与synchronized 不同,获取到锁的线程能够响应中断,当获取到锁的线程被中断时,中断异常将会被抛出,同时锁会被释放。
- 超时获取锁:在指定的截止时间之前获取锁,如果截止时间到了仍旧无法获取锁,则返回
Lock 接口
先来看一下 Lock 接口的类关系图:
Lock 接口的使用也很简单:
1 | Lock lock = new ReentrantLock(); |
在finally块中释放锁,目的是保证在获取到锁之后,最终能够被释放。
另外,不要讲获取锁的过程写在try块中,因为如果在获取锁时发生了异常,异常抛出的同时,也会导致锁无故释放。
Lock 是一个接口,它定义了锁获取和释放的基本操作,Lock的API如下:
- lock():获取锁,调用该方法后当前线程会获取锁,并返回
- lockInterruptibly():可中断地获取锁,该方法可以相应中断,在锁的获取中可以中断当前线程
- tryLock():尝试非阻塞地获取锁,调用该方法会立刻返回,成功获取锁返回true,否则返回false
- tryLock(long time, TimeUnit unit):超时地获取锁
- unlock():释放锁
- newCondition():获取等待通知组件,该组件和当前的锁绑定,当前线程只有获得了锁,才能调用该组件的wait方法,而调用后,当前线程释放锁